home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / TURB_VIS / TCYBER25 / CYBASE.ZIP / CYBASE.PAS < prev    next >
Pascal/Delphi Source File  |  1994-10-20  |  48KB  |  1,813 lines

  1. {
  2. Turbo Vision CyberTools 2.5
  3. (C) 1994 Steve Goldsmith
  4. All Rights Reserved
  5.  
  6. CyberBase application using Paradox Engine 3.x and PX Edit to edit multiple
  7. Paradox tables on single user or network systems.  Table passwords,
  8. encryption, decryption, create, append, copy, rename, empty, delete and
  9. upgrade are supported.  Primary, secondary, composite and case insensitive
  10. indexes can be created and deleted.  The table editor can copy and paste
  11. fields using the standard clip board.  This allows easy import and export of
  12. blob memo fields up to 64K or standard field types.
  13.  
  14. Floating status bar reports what the app is doing during some operations.
  15.  
  16. Borland Pascal 7.x or Turbo Pascal 7.x, Turbo Vision 2.x and Paradox
  17. Engine 3.x Database Framework are required to compile.
  18.  
  19. Set IDE directories to
  20.  
  21. \BP\UNITS;
  22. \BP\EXAMPLES\DOS\TVDEMO;
  23. \BP\EXAMPLES\DOS\TVFM;
  24. \BP\PXENGINE\PASCAL\SOURCE;
  25. \BP\PXENGINE\PASCAL;
  26.  
  27. I used \BP\PXENGINE when I installed Paradox Engine 3.x.  The rest of the
  28. path names use BP 7.x defaults.  If you changed any of these then use the
  29. correct paths in Options|Directories...  See APP.INC for global compiler
  30. switches.
  31.  
  32. * * *  I M P O R T A N T  * * *
  33.  
  34. Remember to add TCursor.getTableHandle method to the Data Base Framework in
  35. \BP\PXENGINE\PASCAL\SOURCE\OOPXENG.PAS.  This allows PX Edit access to
  36. TCursor's private table handle tabH.  PX Edit can then search on the primary
  37. index regardless of what index the table is opened on.
  38.  
  39. Search OOPXENG.PAS for 'searchIndex'. Right after:
  40.  
  41.   function searchIndex(keyRec: PRecord; mode: PXSearchMode;
  42.     fldCnt: Integer): Retcode; virtual;
  43.  
  44. ADD:
  45.  
  46.   function getTableHandle : TableHandle;
  47.  
  48.  
  49. Search OOPXENG.PAS for 'TRecord methods'.  Right before:
  50.  
  51. *************************************************************************
  52.                           TRecord methods
  53. **************************************************************************
  54.  
  55. ADD:
  56.  
  57. function TCursor.getTableHandle : TableHandle;
  58.  
  59. begin
  60.   getTableHandle := tabH
  61. end;
  62.  
  63. USING WITH NETWORKS
  64.  
  65. All groups of users that will be sharing tables must have read/write access
  66. to the network control file PDOXUSRS.NET created by the engine or another
  67. Paradox app.  If you enable DOS share option then SHARE.EXE must be loaded.
  68. If SHARE.EXE is not detected then all table functions are disabled.  See
  69. Options|Engine... dialog to set Engine settings.  CyberBase has been tested
  70. under MS-DOS, Windows 3.1, Novell via Tokenring and Lantastic with a mix of
  71. Engine and Paradox DOS/Windows apps running.
  72. }
  73.  
  74. {$I APP.INC}
  75. {$X+}
  76.  
  77. program CyberBase;
  78.  
  79. uses
  80.  
  81.   Dos,                               {system units}
  82.   OOPXEng, PXEngine,                 {paradox engine 3 and framework units}
  83.   Memory, Drivers, Objects,          {tv units}
  84.   Views, Menus, Dialogs, Editors,
  85.   App, MsgBox, StdDlg, ColorSel,
  86.   Gadgets, Calendar, Calc, HelpFile, {tv demo units}
  87.   ViewText,                          {tvfm units}
  88.   CBHelp, CBCmds, TVStr,             {cybertools units}
  89.   CommDlgs, PXEdit;
  90.  
  91. const
  92.  
  93.   appViewDocBuf = 8192;       {buffer size for viewing doc file}
  94.   appHelpInUse  = $8000;      {used by help system}
  95.   appHelpName = 'CBHELP.HLP'; {help file name}
  96.   appExeName  = 'CYBASE.EXE'; {name used to locate .exe for older dos}
  97.   appDocName  = 'CYBER.DOC';  {doc file name}
  98.   appCfgName = 'CYBASE.CFG';  {config file name}
  99.   appCfgHeaderLen = 10;       {header used by config stream}
  100.   appCfgHeader : string[appCfgHeaderLen] = 'CYBERBASE'#26;
  101.   appTableCmds = [cmOpenTable,cmCreateTable,cmCreateIndex,cmDeleteIndex,
  102.   cmAppendTable,cmCopyTable,cmRenameTable,cmDeleteTable,cmEmptyTable,
  103.   cmUpgradeTable,cmEncryptTable,cmDecryptTable,cmAddPassword]; {engine commands}
  104.  
  105.   CAppStatusLine = #10#10#10#10; {new input line palette to map into app palette}
  106.   CSysColor      = #$00#$00#$00; {app palette additions for tv system stuff}
  107.   CSysPal        = #136#137#138;
  108.  
  109. type
  110.  
  111.   PAppStatusLine = ^TAppStatusLine;
  112.   TAppStatusLine = object (TInputLine)
  113.     function GetPalette: PPalette; virtual;
  114.   end;
  115.  
  116.   TCyberBase = object(TApplication)
  117.     AppOptions : word;
  118.     appEnv : TEnv;
  119.     appEngine : TEngine;
  120.     appDatabase : TDatabase;
  121.     appStatus : PAppStatusLine;
  122.     Clock : PClockView;
  123.     Heap : PHeapView;
  124.     ClipWindow : PCyEditWindow;
  125.     constructor Init;
  126.     destructor Done; virtual;
  127.     procedure UpdateStatus (S : string);
  128.     function ErrorBox (ErrCode : integer) : boolean;
  129.     procedure AboutBox;
  130.     procedure Idle; virtual;
  131.     procedure ClearDeskTop;
  132.     function OpenEditor (FileName : FNameStr; Visible : Boolean) : PCyEditWindow;
  133.     procedure AddPassword;
  134.     procedure RestoreDesktop (F : PathStr);
  135.     procedure SaveDeskTop (F : PathStr);
  136.     procedure GetEvent (var Event : TEvent); virtual;
  137.     function GetPalette : PPalette; virtual;
  138.     procedure HandleEvent(var Event: TEvent); virtual;
  139.     procedure InitDeskTop; virtual;
  140.     procedure InitMenuBar; virtual;
  141.     procedure InitStatusLine; virtual;
  142.     procedure OutOfMemory; virtual;
  143.     procedure LoadDesktop (var S : TStream);
  144.     procedure StoreDesktop (var S : TStream);
  145.   end;
  146.  
  147. {
  148. Make input line look right when inserted into app.
  149. }
  150.  
  151. function TAppStatusLine.GetPalette: PPalette;
  152.  
  153. const
  154.   P: String[Length(CAppStatusLine)] = CAppStatusLine;
  155.  
  156. begin
  157.   GetPalette := @P;
  158. end;
  159.  
  160. {
  161. Init app, engine and database.  If SHARE detection, engine or database
  162. initilization fails then table related commands will be disabled.
  163. }
  164.  
  165. constructor TCyberBase.Init;
  166.  
  167. var
  168.  
  169.   R : TRect;
  170.  
  171. begin
  172.   MaxHeapSize := 12288; {192K app heap}
  173.   LowMemSize := 4095;   {safety pool size}
  174.   inherited Init;
  175.   RegisterObjects;      {register stuff for stream access}
  176.   RegisterViews;
  177.   RegisterMenus;
  178.   RegisterDialogs;
  179.   RegisterApp;
  180.   RegisterHelpFile;
  181.   RegisterEditors;
  182.  
  183.   GetExtent (R);   {gadgets included with tvdemo}
  184.   R.A.Y := R.B.Y-1;
  185.   R.B.X := R.B.X-1;
  186.   R.A.X := R.B.X-8;
  187.   Heap := New (PHeapView,Init(R));
  188.   Heap^.GrowMode := gfGrowAll;
  189.   Insert (Heap);
  190.  
  191.   GetExtent (R);
  192.   R.B.Y := R.A.Y+1;
  193.   R.B.X := R.B.X-1;
  194.   R.A.X := R.B.X-8;
  195.   Clock := New (PClockView,Init (R));
  196.   Insert (Clock);
  197.  
  198.   GetExtent (R); {floating status line}
  199.   R.A.Y := R.B.Y-3;
  200.   R.B.Y := R.A.Y+1;
  201.   R.B.X := R.B.X-2;
  202.   R.A.X := R.B.X-20;
  203.   appStatus := New (PAppStatusLine,Init (R,30));
  204.   appStatus^.Options := appStatus^.Options and not ofSelectable;
  205.   appStatus^.GrowMode := gfGrowAll;
  206.   appStatus^.SetState (sfShadow,true);
  207.   Insert (appStatus);
  208.  
  209.   UpdateStatus ('Starting engine');
  210.   RestoreDesktop (appCfgName);        {load config stream}
  211.   if (appEnv.dosShare <> pxNoShare) and (not ShareInstalled) then
  212.   begin {share not installed, but was requested by engine config}
  213.     MessageBox ('SHARE.EXE not detected.  Exit and run SHARE.EXE or set DOS share to None in Options|Engine.',
  214.     nil, mfError or mfOKButton);
  215.     DisableCommands (appTableCmds)
  216.   end;
  217.   appEngine.Init (@appEnv);           {init engine}
  218.   if ErrorBox (appEngine.lastError) then
  219.     DisableCommands (appTableCmds)
  220.   else                           {set 3.5 compatible or 4.0 create mode}
  221.     ErrorBox (appEngine.setTblCreateMode (appEnv.tabCrtMode));
  222.   appDatabase.Init (@appEngine);      {init database}
  223.   if ErrorBox (appDataBase.lastError) then
  224.     DisableCommands (appTableCmds);
  225.   UpdateStatus ('');
  226.   AboutBox;
  227.   EditorDialog := StdEditorDialog;
  228.   ClipWindow := OpenEditor ('', false); {create clip board}
  229.   if ClipWindow <> nil then
  230.   begin
  231.     Clipboard := ClipWindow^.Editor;
  232.     Clipboard^.CanUndo := false
  233.   end
  234.   else {unable to allocate clip board}
  235.     DisableCommands ([cmShowClip]);
  236.   DisableCommands ([cmSave, cmSaveAs, cmCut, cmCopy, cmPaste, cmClear,
  237.   cmUndo, cmFind, cmReplace, cmSearchAgain, cmCloseAll])
  238. end;
  239.  
  240. {
  241. Close database and engine if open before calling inherited done.
  242. }
  243.  
  244. destructor TCyberBase.Done;
  245.  
  246. begin
  247.   UpdateStatus ('Ending engine');
  248.   if appDataBase.isOpen then
  249.     appDatabase.Done;
  250.   if appEngine.isOpen then
  251.     appEngine.Done;
  252.   inherited Done
  253. end;
  254.  
  255. {
  256. Update dialog status line.
  257. }
  258.  
  259. procedure TCyberBase.UpdateStatus (S : string);
  260.  
  261. begin
  262.   if S = '' then
  263.   begin
  264.     if appStatus^.State and sfVisible <> 0 then
  265.       appStatus^.Hide
  266.   end
  267.   else
  268.   begin
  269.     if appStatus^.State and sfVisible = 0 then
  270.       appStatus^.Show
  271.   end;
  272.   appStatus^.SetData (S)
  273. end;
  274.  
  275. {
  276. Display error and return true if error <> PXSUCCESS.  If error = PXSUCCESS
  277. then no error is diaplayed and false is returned.
  278. }
  279.  
  280. function TCyberBase.ErrorBox (ErrCode : integer) : boolean;
  281.  
  282. begin
  283.   if ErrCode <> PxSuccess then
  284.   begin
  285.     MessageBox (appEngine.getErrorMessage (ErrCode)+'.',
  286.     nil, mfError or mfOKButton);
  287.     ErrorBox := true
  288.   end
  289.   else
  290.     ErrorBox := false
  291. end;
  292.  
  293. {
  294. Tells what the app is about, run, network and share mode info.
  295. }
  296.  
  297. procedure TCyberBase.AboutBox;
  298.  
  299. var
  300.  
  301.   S : string;
  302.  
  303. begin
  304.   S := '';
  305.   if appEnv.engineType <> pxLocal then
  306.     S := S+', NETWORK';
  307.   if appEnv.dosShare <> pxNoShare then
  308.     S := S+', SHARE';
  309.   HelpCtx := hcAbout;
  310.   MessageBox(
  311.     #3'Turbo Vision CyberTools 2.5'#13+
  312.     #3'(C) 1994 Steve Goldsmith'#13+
  313. {$IFDEF DPMI}
  314.     #3'CyberBase DPMI'+S,
  315. {$ELSE}
  316.     #3'CyberBase REAL'+S,
  317. {$ENDIF}
  318.     nil, mfInformation or mfOKButton);
  319.   HelpCtx := hcNoContext
  320. end;
  321.  
  322. {
  323. Update menu, status line and gadgets during idle processing.
  324. }
  325.  
  326. procedure TCyberBase.Idle;
  327.  
  328. {return true if any view on desk top is tileable}
  329.  
  330. function IsTileable (P : PView) : boolean; far;
  331.  
  332. begin
  333.   IsTileable := (P^.Options and ofTileable <> 0) and
  334.   (P^.State and sfVisible <> 0)
  335. end;
  336.  
  337. begin
  338.   inherited Idle;
  339.   Clock^.Update;                                       {update tvdemo gadgets}
  340.   Heap^.Update;
  341.   if Desktop^.Current <> nil then                      {see if anything is}
  342.   begin                                                {on the desk top}
  343.     EnableCommands ([cmCloseAll]);
  344.     if Desktop^.FirstThat (@IsTileable) <> nil then    {see if any tileable}
  345.       EnableCommands ([cmTile,cmCascade])              {windows are on the}
  346.     else                                               {desk top}
  347.       DisableCommands ([cmTile,cmCascade])
  348.   end
  349.   else
  350.     DisableCommands ([cmCloseAll,cmTile,cmCascade]);
  351.   if ((Desktop^.Current <> nil) and
  352.   (Desktop^.Current^.State and sfModal = sfModal)) or
  353.   (AppOptions and appHelpInUse = appHelpInUse) then    {see if modal dialog}
  354.     DisableCommands ([cmQuit,cmOpenTable])             {is on the desk top}
  355.   else
  356.   begin                                                {no modal views}
  357.     if appStatus^.Data^ <> '' then
  358.       UpdateStatus ('');
  359.     if appDataBase.isOpen then                         {enable open table}
  360.       EnableCommands ([cmQuit,cmOpenTable])            {if database is valid}
  361.     else
  362.       EnableCommands ([cmQuit])
  363.   end
  364. end;
  365.  
  366. {
  367. Close all windows on desk top.
  368. }
  369.  
  370. procedure TCyberBase.ClearDeskTop;
  371.  
  372. procedure CloseDlg (P : PView); far;
  373.  
  374. begin
  375.   Message (P,evCommand,cmClose,nil)
  376. end;
  377.  
  378. begin
  379.   UpdateStatus ('Clearing desk top');
  380.   Desktop^.ForEach (@CloseDlg)
  381. end;
  382.  
  383. {
  384. Open text editor.
  385. }
  386.  
  387. function TCyberBase.OpenEditor (FileName : FNameStr; Visible : Boolean) : PCyEditWindow;
  388.  
  389. var
  390.  
  391.   R : TRect;
  392.   P : PWindow;
  393.  
  394. begin
  395.   DeskTop^.GetExtent (R);
  396.   P := New (PCyEditWindow, Init (R, FileName, wnNoNumber));
  397.   P^.HelpCtx := hcTextEditor;
  398.   if not Visible then
  399.     P^.Hide;
  400.   OpenEditor := PCyEditWindow (Application^.InsertWindow (P))
  401. end;
  402.  
  403. {
  404. Add master password to engine.
  405. }
  406.  
  407. procedure TCyberBase.AddPassword;
  408.  
  409. var
  410.  
  411.   Password : string;
  412.  
  413. begin
  414.   HelpCtx := hcPasswordDialog;
  415.   Password := '';
  416.   if InputBox ('','Password',Password,15) <> cmCancel then
  417.     ErrorBox (appEngine.addPassword (Password));
  418.   HelpCtx := hcNoContext
  419. end;
  420.  
  421. {
  422. Restore desk top stream.
  423. }
  424.  
  425. procedure TCyberBase.RestoreDesktop (F : PathStr);
  426.  
  427. var
  428.  
  429.   S : PStream;
  430.   Signature : string[appCfgHeaderLen];
  431.  
  432. begin
  433.   S := New (PBufStream,Init (F,stOpenRead,1024));
  434.   if LowMemory then OutOfMemory
  435.   else
  436.     if S^.Status <> stOk then
  437.     begin
  438.       MessageBox (#3'Unable to open file.',nil,mfOkButton+mfError)
  439.     end
  440.     else
  441.     begin
  442.       Signature[0] := Char (appCfgHeaderLen);
  443.       S^.Read (Signature[1],appCfgHeaderLen);
  444.       if Signature = appCfgHeader then {see if signature is right}
  445.       begin
  446.         S^.Read (appEnv,SizeOf (appEnv)); {read data from stream}
  447.         LoadDesktop (S^);
  448.         LoadIndexes (S^);
  449.         ShadowAttr := GetColor (136);   {tv shadow color}
  450.         SysColorAttr := (GetColor (137) shl 8) or GetColor (137); {tv system error color}
  451.         ErrorAttr := GetColor (138);    {tv palette index error color}
  452.         Application^.ReDraw; {draw app with new config}
  453.         if S^.Status <> stOk then
  454.           MessageBox (#3'Stream error.',nil,mfOkButton+mfError);
  455.       end
  456.       else
  457.         MessageBox (#3'Invalid configuration format.',nil,mfOkButton+mfError)
  458.     end;
  459.   Dispose (S,Done)
  460. end;
  461.  
  462. {
  463. Save desk top stream.
  464. }
  465.  
  466. procedure TCyberBase.SaveDesktop (F : PathStr);
  467.  
  468. var
  469.  
  470.   CfgFile : File;
  471.   S : PStream;
  472.  
  473. begin
  474.   S := New(PBufStream,Init (F,stCreate,1024));
  475.   if not LowMemory and (S^.Status = stOk) then
  476.   begin
  477.     S^.Write (appCfgHeader[1],appCfgHeaderLen);
  478.     S^.Write (appEnv,SizeOf (appEnv));
  479.     StoreDesktop (S^);
  480.     StoreIndexes (S^);
  481.     if S^.Status <> stOk then
  482.     begin {if stream error then delete file}
  483.       MessageBox (#3'Could not create stream.',nil,mfOkButton+mfError);
  484.       Dispose (S,Done);
  485.       Assign (CfgFile,F);
  486.       {$I-} Erase (CfgFile) {$I+};
  487.       Exit
  488.     end
  489.   end;
  490.   Dispose (S,Done)
  491. end;
  492.  
  493. {
  494. Intercept cmHelp to display help even when views are in modal state.
  495. }
  496.  
  497. procedure TCyberBase.GetEvent (var Event : TEvent);
  498.  
  499. function CalcHelpName : PathStr;
  500.  
  501. var
  502.  
  503.   EXEName : PathStr;
  504.   Dir : DirStr;
  505.   Name : NameStr;
  506.   Ext : ExtStr;
  507.  
  508. begin
  509.   if Lo (DosVersion) >= 3 then
  510.     EXEName := ParamStr (0)
  511.   else
  512.     EXEName := FSearch (appExeName, GetEnv ('PATH'));
  513.   FSplit (EXEName, Dir, Name, Ext);
  514.   if Dir[Length (Dir)] = '\' then
  515.     Dec (Dir[0]);
  516.   CalcHelpName := FSearch (appHelpName, Dir);
  517. end;
  518.  
  519. var
  520.  
  521.   W : PWindow;
  522.   HFile : PHelpFile;
  523.   HelpStrm : PDosStream;
  524.  
  525. begin
  526.   inherited GetEvent (Event);
  527.   case Event.What of
  528.     evCommand:
  529.       if (Event.Command = cmHelp) and (AppOptions and appHelpInUse = 0) then
  530.       begin {process help command if not in use}
  531.         AppOptions := AppOptions or appHelpInUse; {help's in use}
  532.         HelpStrm := New (PDosStream, Init (CalcHelpName, stOpenRead));
  533.         HFile := New (PHelpFile, Init (HelpStrm));
  534.         if HelpStrm^.Status <> stOk then
  535.         begin
  536.           MessageBox (#3'Could not open help file.', nil, mfError + mfOkButton);
  537.           Dispose (HFile, Done);
  538.         end
  539.         else
  540.         begin
  541.           W := New (PHelpWindow,Init (HFile, GetHelpCtx));
  542.           if ValidView (W) <> nil then
  543.           begin
  544.             DisableCommands ([cmHelp]);
  545.             ExecView (W);
  546.             Dispose (W, Done);
  547.             EnableCommands ([cmHelp])
  548.           end;
  549.           ClearEvent (Event)
  550.         end;
  551.         AppOptions := AppOptions and not appHelpInUse
  552.       end;
  553.     evMouseDown:
  554.       if Event.Buttons <> 1 then
  555.         Event.What := evNothing
  556.   end
  557. end;
  558.  
  559. {
  560. Get custom app palette.
  561. }
  562.  
  563. function TCyberBase.GetPalette: PPalette;
  564.  
  565. const
  566.  
  567.   CNewColor = CAppColor+CHelpColor+CSysColor;
  568.   CNewBlackWhite = CAppBlackWhite+CHelpBlackWhite+CSysColor;
  569.   CNewMonochrome = CAppMonochrome+CHelpMonochrome+CSysColor;
  570.   P: array[apColor..apMonochrome] of string[Length (CNewColor)] =
  571.   (CNewColor, CNewBlackWhite, CNewMonochrome);
  572.  
  573. begin {add additional entries to the normal application palettes}
  574.   GetPalette := @P[AppPalette];
  575. end;
  576.  
  577. {
  578. Handle app events.
  579. }
  580.  
  581. procedure TCyberBase.HandleEvent(var Event: TEvent);
  582.  
  583. {
  584. Configure and save engine setup.  Be careful when modifing engine values,
  585. since incorrect values can crash the engine with a internal error!
  586. }
  587.  
  588. procedure EngineConfig;
  589.  
  590. var
  591.  
  592.   D : PpxeEngineCfg;
  593.   CfgRec : TpxeEngineCfgRec;
  594.  
  595. begin
  596.   EngCfgToDlgCfg (appEnv,CfgRec);
  597.   D := New (PpxeEngineCfg,Init);
  598.   D^.HelpCtx := hcEngineDialog;
  599.   if ExecuteDialog (D,@CfgRec) <> cmCancel then
  600.   begin
  601.     DlgCfgToEngCfg (CfgRec,appEnv);
  602.     MessageBox(
  603.     'Engine changes will not take effect until you save configuration as '+
  604.     appCfgName+' and reload program.',
  605.     nil, mfInformation or mfOKButton)
  606.   end
  607. end;
  608.  
  609. {
  610. Tree window.
  611. }
  612.  
  613. procedure TreeWindow (T : string; FMask : PathStr; ACmd : word);
  614.  
  615. var
  616.  
  617.   W : PDirWindow;
  618.   Drive : PathStr;
  619.  
  620. begin
  621.   GetDir (0,Drive);
  622.   W := New (PDirWindow,Init (T,Drive,FMask,ACmd));
  623.   W^.HelpCtx := hcTreeWindow;
  624.   InsertWindow (W)
  625. end;
  626.  
  627. {
  628. Return focused file name from dir tree window.  If the extension param is not
  629. null then that extension is used.
  630. }
  631.  
  632. function TreeFileName (TW : PDirWindow; EStr : PathStr; ReadFlag : boolean) : PathStr;
  633.  
  634. var
  635.  
  636.   F : file;
  637.   FName : PathStr;
  638.  
  639. begin
  640.   FName := UpCaseStr (TW^.FocDirName+TW^.NameLine^.Data^);
  641.   if (EStr <> '') and (FName[byte (FName[0])] <> '\') then {force extension}
  642.     FName := AddExtStr (FName,EStr);
  643.   if ReadFlag then
  644.     TreeFileName := FName
  645.   else
  646.   begin
  647.     Assign (F,FName);
  648.     {$I-} Reset (F); {$I+}
  649.     if IoResult = 0 then {see if file exists before writes}
  650.     begin
  651.       {$I-} Close (F); {$I+}
  652.       if MessageBox (FName+' already exists.  Erase and continue?',
  653.       nil,mfConfirmation or mfYesNoCancel) = cmYes then
  654.         TreeFileName := FName
  655.       else
  656.         TreeFileName := ''
  657.     end
  658.     else
  659.       TreeFileName := FName {doesn't exist, so return name}
  660.   end
  661. end;
  662.  
  663. {
  664. New file list.
  665. }
  666.  
  667. procedure NewFileList;
  668.  
  669. var
  670.  
  671.   D : PStrListDlg;
  672.  
  673. begin
  674.   D := New (PStrListDlg,Init ('File List'));
  675.   D^.HelpCtx := hcFileList;
  676.   InsertWindow (D)
  677. end;
  678.  
  679. {
  680. Add file to file list.
  681. }
  682.  
  683. procedure AddFileToList (TW : PDirWindow);
  684.  
  685. var
  686.  
  687.   I : integer;
  688.   F : PathStr;
  689.   D : PStrListDlg;
  690.  
  691. function IsStrList (V : PView) : boolean; far;
  692.  
  693. begin
  694.   IsStrList :=  TypeOf (V^) = TypeOf (TStrListDlg)
  695. end;
  696.  
  697. begin
  698.   F := TreeFileName (TW,'',true);
  699.   if F <> '' then
  700.   begin
  701.     D := PStrListDlg (Desktop^.FirstThat (@IsStrList));
  702.     if D <> nil then
  703.       with D^.StrBox^ do
  704.       begin
  705.         if (not LowMemory) and
  706.         (not PStringCollection (List)^.Search (@F,I)) then
  707.         begin
  708.           List^.Insert (NewStr(F));       {add file name to list}
  709.           SetRange (List^.Count);         {set list's range}
  710.           FocusItem (List^.IndexOf (@F)); {focus inserted item}
  711.           DrawView                        {draw box}
  712.         end
  713.       end
  714.   end
  715. end;
  716.  
  717. {
  718. Return first file list in Z order.
  719. }
  720.  
  721. function GetStrListDlg : PStrListDlg;
  722.  
  723. function IsStrList (V : PView) : boolean; far;
  724.  
  725. begin
  726.   IsStrList :=  TypeOf (V^) = TypeOf (TStrListDlg)
  727. end;
  728.  
  729. begin
  730.   GetStrListDlg := PStrListDlg (Desktop^.FirstThat (@IsStrList))
  731. end;
  732.  
  733. {
  734. Find first file list in Z order and handle missing and empty lists by
  735. returning nil.
  736. }
  737.  
  738. function GetFileList : PStrListDlg;
  739.  
  740. var
  741.  
  742.   D : PStrListDlg;
  743.  
  744. begin
  745.   D := GetStrListDlg;
  746.   if D <> nil then
  747.   begin
  748.     if D^.StrBox^.List^.Count = 0 then
  749.     begin
  750.       MessageBox (#3'File list empty',nil,mfOkButton+mfError);
  751.       D^.Focus;
  752.       D := nil
  753.     end
  754.   end
  755.   else
  756.   begin
  757.     MessageBox (#3'No file list found on desk top',nil,mfOkButton+mfError);
  758.     NewFileList;
  759.     D := nil
  760.   end;
  761.   GetFileList := D
  762. end;
  763.  
  764. {
  765. Load .CFG file.
  766. }
  767.  
  768. procedure LoadConfigFile (TW : PDirWindow);
  769.  
  770. var
  771.  
  772.   F : PathStr;
  773.  
  774. begin
  775.   F := TreeFileName (TW,'CFG',true);
  776.   if F <> '' then
  777.     RestoreDeskTop (F)
  778. end;
  779.  
  780. {
  781. Save .CFG file.
  782. }
  783.  
  784. procedure SaveConfigFile (TW : PDirWindow);
  785.  
  786. var
  787.  
  788.   F : PathStr;
  789.  
  790. begin
  791.   F := TreeFileName (TW,'CFG',false);
  792.   if F <> '' then
  793.     SaveDeskTop (F)
  794. end;
  795.  
  796. {
  797. Open new table editor window on selected index.  If no index or only a primary
  798. exists then table is opened without prompting for key.  Handles encrypted
  799. tables too.
  800. }
  801.  
  802. procedure OpenTable (TW : PDirWindow);
  803.  
  804. var
  805.  
  806.   KeyCmd : word;
  807.   FileName : PathStr;
  808.   OpenFldNum : FieldNumber;
  809.   GetError : Retcode;
  810.   BrowseCur : PCursor;
  811.   W : PpxeTableWin;
  812.   K : PpxeKeyDialog;
  813.   KData : TpxeKeyDlgRec;
  814.  
  815. begin
  816.   FileName := TreeFileName (TW,'DB',true);
  817.   if FileName <> '' then
  818.   begin
  819.     UpdateStatus ('Reading indexes');
  820.     GetError := GetKeyFieldDesc (FileName,
  821.     @appDataBase,KData.Fields.List);     {get field descs}
  822.     KData.Fields.Selection := 0;
  823.     if GetError = PXERR_INSUFRIGHTS then {handle password}
  824.     begin
  825.       AddPassword;
  826.       GetError := GetKeyFieldDesc (FileName,
  827.       @appDataBase,KData.Fields.List)    {get field descs}
  828.     end;
  829.     UpdateStatus ('');
  830.     if not ErrorBox (GetError) then  {no errors, so proceed}
  831.     begin
  832.       if (KData.Fields.List <> nil) and
  833.       (KData.Fields.List^.Count > 1) then
  834.       begin {select key to open on}
  835.         K := New (PpxeKeyDialog,Init (FileName));
  836.         K^.HelpCtx := hcOpenIndexDialog;
  837.         KeyCmd := ExecuteDialog (K,@KData);
  838.         if KeyCmd <> cmCancel then
  839.           OpenFldNum := PFieldDesc (KData.Fields.List^.At (
  840.           KData.Fields.Selection))^.fldNum
  841.       end
  842.       else {no keys or only primary key}
  843.       begin
  844.         OpenFldNum := 0;
  845.         KeyCmd := cmOk
  846.       end;
  847.       if KeyCmd <> cmCancel then
  848.       begin
  849.         UpdateStatus ('Opening table');
  850.         BrowseCur := New (PCursor,
  851.         InitAndOpen (@appDataBase,FileName,OpenFldNum,true));
  852.         if not ErrorBox (BrowseCur^.lastError) then
  853.         begin {create table editor}
  854.           W := New (PpxeTableWin,Init (FileName,
  855.           @appEngine,@appDataBase,BrowseCur,OpenFldNum));
  856.           W^.HelpCtx := hcTableEditor;
  857.           InsertWindow (W)
  858.         end
  859.         else {dispose cursor if error}
  860.           Dispose (BrowseCur,Done)
  861.       end
  862.     end;
  863.     if KData.Fields.List <> nil then
  864.       Dispose (KData.Fields.List,Done)
  865.   end
  866. end;
  867.  
  868. {
  869. Create table with password and error retry.  If appDataBase.createTable
  870. returns an error you can retry with another table name, edit fields again or
  871. abort.
  872. }
  873.  
  874. procedure CreateTable (TW : PDirWindow);
  875.  
  876. var
  877.  
  878.   ExitCreate : boolean;
  879.   FileName : PathStr;
  880.   CreateData : TpxeCreateDlgRec;
  881.   D : PpxeCreateDialog;
  882.  
  883. begin
  884.   FillChar (CreateData,SizeOf (CreateData),0); {zero dialog rec}
  885.   repeat
  886.     UpdateStatus ('');
  887.     ExitCreate := true;
  888.     FileName := TreeFileName (TW,'DB',false);
  889.     if FileName <> '' then
  890.     begin
  891.       if CreateData.Fields.List = nil then {create new list}
  892.         CreateData.Fields.List := New (PCollection,Init (255,0));
  893.       D := New (PpxeCreateDialog,Init (FileName,CreateData.Fields.List));
  894.       D^.HelpCtx := hcCreateDialog;
  895.       if ExecuteDialog (D,@CreateData) <> cmCancel then
  896.       begin
  897.         UpdateStatus ('Creating table');
  898.         if appDataBase.createTable (FileName,
  899.         CreateData.Fields.List) = PXERR_INSUFRIGHTS then
  900.         begin {handle password}
  901.           AddPassword;
  902.           ErrorBox (appDataBase.createTable (FileName,
  903.           CreateData.Fields.List))
  904.         end
  905.         else
  906.           ErrorBox (appDataBase.lastError);
  907.         if appDataBase.lastError <> PXSUCCESS then {error, try again?}
  908.           if MessageBox ('Try again?',
  909.           nil,mfConfirmation or mfYesNoCancel) = cmYes then
  910.             ExitCreate := false
  911.       end;
  912.       if ExitCreate then {dispose list if exiting}
  913.         Dispose (CreateData.Fields.List,Done)
  914.     end
  915.   until ExitCreate
  916. end;
  917.  
  918. {
  919. Create primary, single/multi field secondary and/or case-insensitive index.
  920. }
  921.  
  922. procedure CreateIndex (TW : PDirWindow);
  923.  
  924. var
  925.  
  926.   I, FldCnt : integer;
  927.   FileName : PathStr;
  928.   GetError : Retcode;
  929.   FldHan : FieldHandle;
  930.   FldHanArr : FieldNumberArray;
  931.   IData : TpxeIndexDlgRec;
  932.   D : PpxeIndexDialog;
  933.  
  934. begin
  935.   FillChar (IData,SizeOf (IData),0); {zero dialog rec}
  936.   FileName := TreeFileName (TW,'DB',true);
  937.   if FileName <> '' then
  938.   begin
  939.     IData.Fields.List := nil;        {start with nil lists}
  940.     IData.Key.List := nil;
  941.     GetError := GetFieldDesc (FileName,  {get field descs}
  942.     @appDataBase,IData.Fields.List);
  943.     if GetError = PXERR_INSUFRIGHTS then {handle password}
  944.     begin
  945.       AddPassword;
  946.       GetError := GetFieldDesc (FileName,
  947.       @appDataBase,IData.Fields.List)
  948.     end;
  949.     if not ErrorBox (GetError) then  {no errors, so proceed}
  950.     begin
  951.       FldCnt := IData.Fields.List^.Count;  {field count}
  952.       D := New (PpxeIndexDialog,Init (FileName));
  953.       IData.Key.List := New (PCollection,Init (FldCnt,0));
  954.       D^.FieldPtr := IData.Fields.List; {let dialog know where list is}
  955.       D^.HelpCtx := hcCreateIndexDialog;
  956.       if ExecuteDialog (D,@IData) <> cmCancel then
  957.       begin
  958.         UpdateStatus ('Indexing table');
  959.         if IData.Key.List^.Count > 0 then {any fields selected?}
  960.         begin
  961.           if PXKeyCrtMode (IData.Index) = pxPrimary then
  962.           begin {use field number as field count of primary key}
  963.             ErrorBox (appDataBase.createPIndex (FileName,
  964.             PFieldDesc (IData.Key.List^.At (0))^.fldNum))
  965.           end
  966.           else {single field case-sensitive secondary index}
  967.             if (IData.Key.List^.Count = 1) and (IData.CaseSens = 0) then
  968.             begin
  969.               ErrorBox (appDataBase.createSIndex (FileName,
  970.               PFieldDesc (IData.Key.List^.At (0))^.fldNum,PXKeyCrtMode (IData.Index)))
  971.             end
  972.             else {multi-field and/or case-sensitive/insensitive secondary index}
  973.             begin
  974.               FldCnt := IData.Key.List^.Count; {total fields}
  975.               for I := 1 to FldCnt do {load field numbers into handle array}
  976.                 FldHanArr[I] := PFieldDesc (IData.Key.List^.At (I-1))^.fldNum;
  977.               if not ErrorBox (appDataBase.defineCompoundKey (
  978.               FileName,FldCnt,FldHanArr,IData.FldName,
  979.               IData.CaseSens = 0,FldHan)) then {make index}
  980.                 ErrorBox (appDataBase.createSIndex (FileName,
  981.                 FldHan,PXKeyCrtMode (IData.Index)))
  982.             end
  983.         end
  984.         else {no fields selected to make index}
  985.           MessageBox (#3'No fields selected.',nil,mfOkButton+mfError)
  986.       end
  987.     end;
  988.     if IData.Fields.List <> nil then {dispose lists}
  989.       Dispose (IData.Fields.List,Done);
  990.     if IData.Key.List <> nil then
  991.       Dispose (IData.Key.List,Done)
  992.   end
  993. end;
  994.  
  995. {
  996. Delete primary, single/multi field secondary or case-insensitive index.
  997. }
  998.  
  999. procedure DeleteIndex (TW : PDirWindow);
  1000.  
  1001. var
  1002.  
  1003.   FileName : PathStr;
  1004.   GetError : Retcode;
  1005.   K : PpxeKeyDialog;
  1006.   KData : TpxeKeyDlgRec;
  1007.  
  1008. begin
  1009.   FileName := TreeFileName (TW,'DB',true);
  1010.   if FileName <> '' then
  1011.   begin
  1012.     UpdateStatus ('Reading indexes');
  1013.     GetError := GetKeyFieldDesc (FileName,
  1014.     @appDataBase,KData.Fields.List);     {get key fields}
  1015.     KData.Fields.Selection := 0;
  1016.     if GetError = PXERR_INSUFRIGHTS then {handle password}
  1017.     begin
  1018.       AddPassword;
  1019.       GetError := GetKeyFieldDesc (FileName,
  1020.       @appDataBase,KData.Fields.List) {get field descs}
  1021.     end;
  1022.     UpdateStatus ('');
  1023.     if not ErrorBox (GetError) then  {no errors, so proceed}
  1024.     begin
  1025.       if KData.Fields.List <> nil then
  1026.       begin {select key to delete}
  1027.         K := New (PpxeKeyDialog,Init (FileName));
  1028.         K^.HelpCtx := hcDeleteIndexDialog;
  1029.         if ExecuteDialog (K,@KData) <> cmCancel then
  1030.         begin
  1031.           UpdateStatus ('Deleting index');
  1032.           ErrorBox (appDataBase.dropIndex (FileName,
  1033.           PFieldDesc (KData.Fields.List^.At (
  1034.           KData.Fields.Selection))^.fldNum))
  1035.         end
  1036.       end
  1037.       else
  1038.         MessageBox (FileName+' has no keys to delete.',nil,mfOkButton+mfError)
  1039.     end;
  1040.     if KData.Fields.List <> nil then
  1041.       Dispose (KData.Fields.List,Done)
  1042.   end
  1043. end;
  1044.  
  1045. {
  1046. Append table with password retry.
  1047. }
  1048.  
  1049. procedure AppendTable (TW : PDirWindow);
  1050.  
  1051. var
  1052.  
  1053.   SFileName,
  1054.   DFileName : PathStr;
  1055.   D : PStrListDlg;
  1056.  
  1057. begin
  1058.   D := GetFileList;
  1059.   if D <> nil then
  1060.   begin
  1061.     SFileName := PString (D^.StrBox^.List^.At (0))^;
  1062.     DFileName := TreeFileName (TW,'DB',true);
  1063.     UpdateStatus ('Appending table');
  1064.     if appDataBase.appendTable (SFileName,DFileName) = PXERR_INSUFRIGHTS then
  1065.     begin
  1066.       AddPassword;
  1067.       ErrorBox (appDataBase.appendTable (SFileName,DFileName))
  1068.     end
  1069.     else
  1070.       ErrorBox (appDataBase.lastError)
  1071.   end
  1072. end;
  1073.  
  1074. {
  1075. Copy table with password retry.
  1076. }
  1077.  
  1078. procedure CopyTable (TW : PDirWindow);
  1079.  
  1080. var
  1081.  
  1082.   SFileName,
  1083.   DFileName : PathStr;
  1084.   D : PStrListDlg;
  1085.  
  1086. begin
  1087.   D := GetFileList;
  1088.   if D <> nil then
  1089.   begin
  1090.     SFileName := PString (D^.StrBox^.List^.At (0))^; {source comes from file list}
  1091.     DFileName := TreeFileName (TW,'DB',false);       {dest comes from file browser}
  1092.     UpdateStatus ('Coping table');
  1093.     if appDataBase.copyTable (SFileName,DFileName) = PXERR_INSUFRIGHTS then
  1094.     begin
  1095.       AddPassword;
  1096.       ErrorBox (appDataBase.copyTable (SFileName,DFileName))
  1097.     end
  1098.     else
  1099.       ErrorBox (appDataBase.lastError)
  1100.   end
  1101. end;
  1102.  
  1103. {
  1104. Rename table with password retry.
  1105. }
  1106.  
  1107. procedure RenameTable (TW : PDirWindow);
  1108.  
  1109. var
  1110.  
  1111.   SFileName,
  1112.   DFileName : PathStr;
  1113.   D : PStrListDlg;
  1114.  
  1115. begin
  1116.   D := GetFileList;
  1117.   if D <> nil then
  1118.   begin
  1119.     SFileName := PString (D^.StrBox^.List^.At (0))^;
  1120.     DFileName := TreeFileName (TW,'DB',true);
  1121.     UpdateStatus ('Renaming table');
  1122.     if appDataBase.renameTable (SFileName,DFileName) = PXERR_INSUFRIGHTS then
  1123.     begin
  1124.       AddPassword;
  1125.       ErrorBox (appDataBase.renameTable (SFileName,DFileName))
  1126.     end
  1127.     else
  1128.       ErrorBox (appDataBase.lastError)
  1129.   end
  1130. end;
  1131.  
  1132. {
  1133. Delete table with password retry.
  1134. }
  1135.  
  1136. procedure DeleteTable (TW : PDirWindow);
  1137.  
  1138. var
  1139.  
  1140.   FileName : PathStr;
  1141.  
  1142. begin
  1143.   FileName := TreeFileName (TW,'DB',true);
  1144.   if FileName <> '' then
  1145.   begin
  1146.     UpdateStatus ('Deleting table');
  1147.     if appDataBase.deleteTable (FileName) = PXERR_INSUFRIGHTS then
  1148.     begin
  1149.       AddPassword;
  1150.       ErrorBox (appDataBase.deleteTable (FileName))
  1151.     end
  1152.     else
  1153.       ErrorBox (appDataBase.lastError)
  1154.   end
  1155. end;
  1156.  
  1157. {
  1158. Upgrade table with password retry.
  1159. }
  1160.  
  1161. procedure UpgradeTable (TW : PDirWindow);
  1162.  
  1163. var
  1164.  
  1165.   FileName : PathStr;
  1166.  
  1167. begin
  1168.   FileName := TreeFileName (TW,'DB',true);
  1169.   if FileName <> '' then
  1170.   begin
  1171.     UpdateStatus ('Upgrading table');
  1172.     if appDataBase.upgradeTable (FileName) = PXERR_INSUFRIGHTS then
  1173.     begin
  1174.       AddPassword;
  1175.       ErrorBox (appDataBase.upgradeTable (FileName))
  1176.     end
  1177.     else
  1178.       ErrorBox (appDataBase.lastError)
  1179.   end
  1180. end;
  1181.  
  1182. {
  1183. Empty table with password retry.
  1184. }
  1185.  
  1186. procedure EmptyTable (TW : PDirWindow);
  1187.  
  1188. var
  1189.  
  1190.   FileName : PathStr;
  1191.  
  1192. begin
  1193.   FileName := TreeFileName (TW,'DB',true);
  1194.   if FileName <> '' then
  1195.   begin
  1196.     UpdateStatus ('Empty table');
  1197.     if appDataBase.emptyTable (FileName) = PXERR_INSUFRIGHTS then
  1198.     begin
  1199.       AddPassword;
  1200.       ErrorBox (appDataBase.emptyTable (FileName))
  1201.     end
  1202.     else
  1203.       ErrorBox (appDataBase.lastError)
  1204.   end
  1205. end;
  1206.  
  1207. {
  1208. Encrypt table with password retry.
  1209. }
  1210.  
  1211. procedure EncryptTable (TW : PDirWindow);
  1212.  
  1213. var
  1214.  
  1215.   FileName : PathStr;
  1216.   Password : string;
  1217.  
  1218. begin
  1219.   FileName := TreeFileName (TW,'DB',true);
  1220.   if FileName <> '' then
  1221.   begin
  1222.     Password := '';
  1223.     if InputBox ('Encrypt','Password',Password,15) <> cmCancel then
  1224.     begin
  1225.       UpdateStatus ('Encrypting table');
  1226.       if appDataBase.encryptTable (FileName,Password) = PXERR_INSUFRIGHTS then
  1227.       begin
  1228.         AddPassword;
  1229.         ErrorBox (appDataBase.encryptTable (FileName,Password))
  1230.       end
  1231.       else
  1232.         ErrorBox (appDataBase.lastError)
  1233.     end
  1234.   end
  1235. end;
  1236.  
  1237. {
  1238. Decrypt table with password retry.  Password must be in effect for decrypt to
  1239. work.
  1240. }
  1241.  
  1242. procedure DecryptTable (TW : PDirWindow);
  1243.  
  1244. var
  1245.  
  1246.   FileName : PathStr;
  1247.  
  1248. begin
  1249.   FileName := TreeFileName (TW,'DB',true);
  1250.   if FileName <> '' then
  1251.   begin
  1252.     UpdateStatus ('Decrypting table');
  1253.     if appDataBase.decryptTable (FileName) = PXERR_INSUFRIGHTS then
  1254.     begin
  1255.       AddPassword;
  1256.       ErrorBox (appDataBase.decryptTable (FileName))
  1257.     end
  1258.     else
  1259.       ErrorBox (appDataBase.lastError)
  1260.   end
  1261. end;
  1262.  
  1263. {
  1264. Switch between 25 and 43/50 line mode and refresh editors.  The table editor
  1265. buffers have been optimized to use only what is needed to view a maximumized
  1266. window.
  1267. }
  1268.  
  1269. procedure ToggleVideo;
  1270.  
  1271. var
  1272.  
  1273.   NewMode : word;
  1274.   R : TRect;
  1275.  
  1276. begin
  1277.   NewMode := ScreenMode xor smFont8x8;
  1278.   if NewMode and smFont8x8 <> 0 then
  1279.     ShadowSize.X := 1
  1280.   else
  1281.     ShadowSize.X := 2;
  1282.   SetScreenMode (NewMode);
  1283.   Desktop^.GetExtent (R);
  1284.   UpdateStatus ('Refresh editor');
  1285.   Message (DeskTop,evBroadcast,cmVideoChange,@Self) {refreash all editors}
  1286. end;
  1287.  
  1288. {
  1289. TV Demo calendar.
  1290. }
  1291.  
  1292. procedure Calendar;
  1293.  
  1294. var
  1295.  
  1296.   P : PCalendarWindow;
  1297.  
  1298. begin
  1299.   P := New (PCalendarWindow, Init);
  1300.   P^.Palette := dpGrayDialog;
  1301.   P^.HelpCtx := hcCalendar;
  1302.   InsertWindow (P)
  1303. end;
  1304.  
  1305. {
  1306. TV Demo calculator.
  1307. }
  1308.  
  1309. procedure Calculator;
  1310.  
  1311. var
  1312.  
  1313.   P : PCalculator;
  1314. begin
  1315.   P := New (PCalculator, Init);
  1316.   P^.HelpCtx := hcCalculator;
  1317.   InsertWindow (P)
  1318. end;
  1319.  
  1320. {
  1321. View doc file.
  1322. }
  1323.  
  1324. procedure ViewTextFile (FileName : PathStr);
  1325.  
  1326. var
  1327.  
  1328.   T : PTextWindow;
  1329.   R : TRect;
  1330.  
  1331. begin
  1332.   GetExtent (R);
  1333.   R.Grow (-5,-4);
  1334.   T := New(PTextWindow, Init(R, FileName));
  1335.   T^.Options := T^.Options or ofCentered;
  1336.   T^.HelpCtx := hcViewDoc;
  1337.   InsertWindow (T)
  1338. end;
  1339.  
  1340. {
  1341. Return focused editor window or nil if none focused.
  1342. }
  1343.  
  1344. function GetEditor (FocFlag : boolean) : PCyEditWindow;
  1345.  
  1346. var
  1347.  
  1348.   FE : PCyEditWindow;
  1349.  
  1350. function IsFocused (V : PView) : boolean; far;
  1351.  
  1352. begin
  1353.   if FocFlag then
  1354.     IsFocused := (TypeOf (V^) = TypeOf (TCyEditWindow)) and
  1355.     (PCyEditWindow (V)^.State and sfFocused <> 0)
  1356.   else
  1357.     IsFocused := (TypeOf (V^) = TypeOf (TCyEditWindow))
  1358. end;
  1359.  
  1360. begin
  1361.   FE := PCyEditWindow (Desktop^.FirstThat (@IsFocused));
  1362.   if FE = nil then
  1363.     MessageBox ('No editor windows focused on desk top.',nil,mfOkButton+mfError);
  1364.   GetEditor := FE
  1365. end;
  1366.  
  1367. {
  1368. Open new text editor.
  1369. }
  1370.  
  1371. procedure FileNew;
  1372.  
  1373.  
  1374. begin
  1375.   OpenEditor ('', True)
  1376. end;
  1377.  
  1378. {
  1379. Open text file.
  1380. }
  1381.  
  1382. procedure FileOpen (TW : PDirWindow);
  1383.  
  1384. var
  1385.  
  1386.   F : PathStr;
  1387.  
  1388. begin
  1389.   F := TreeFileName (TW,'',true);
  1390.   if F <> '' then
  1391.     OpenEditor(F,true)
  1392. end;
  1393.  
  1394. {
  1395. Save as text file.
  1396. }
  1397.  
  1398. procedure SaveFileAs (TW : PDirWindow);
  1399.  
  1400. var
  1401.  
  1402.   F : PathStr;
  1403.   E : PCyEditWindow;
  1404.  
  1405. begin
  1406.   F := TreeFileName (TW,'',false);
  1407.   if F <> '' then
  1408.   begin
  1409.     E := GetEditor (false); {get first editor in z order}
  1410.     if E <> nil then
  1411.     begin
  1412.       E^.Editor^.FileName := F;
  1413.       Message (E^.Owner, evBroadcast, cmUpdateTitle, nil);
  1414.       E^.Editor^.SaveFile;
  1415.       if E^.Editor = @Clipboard then
  1416.         E^.Editor^.FileName := ''
  1417.     end
  1418.   end
  1419. end;
  1420.  
  1421. {
  1422. Make clip window visible.
  1423. }
  1424.  
  1425. procedure ShowClip;
  1426.  
  1427. begin
  1428.   if ClipWindow <> nil then
  1429.   begin
  1430.     ClipWindow^.Select;
  1431.     ClipWindow^.Show
  1432.   end
  1433. end;
  1434.  
  1435. {
  1436. Set custom TV color palette.
  1437. }
  1438.  
  1439. procedure Colors;
  1440.  
  1441. {custom color items}
  1442. function DlgColorItems (Palette: Word; const Next: PColorItem) : PColorItem;
  1443.  
  1444. const
  1445.  
  1446.   COffset : array[dpBlueDialog..dpGrayDialog] of Byte = (64, 96, 32);
  1447.  
  1448. var
  1449.  
  1450.   Offset : Byte;
  1451.  
  1452. begin
  1453.   Offset := COffset[Palette];
  1454.   DlgColorItems :=
  1455.     ColorItem ('Frame passive',     Offset,
  1456.     ColorItem ('Frame active',      Offset + 1,
  1457.     ColorItem ('Frame icons',       Offset + 2,
  1458.     ColorItem ('Scroll bar page',   Offset + 3,
  1459.     ColorItem ('Scroll bar icons',  Offset + 4,
  1460.     ColorItem ('Static text',       Offset + 5,
  1461.  
  1462.     ColorItem ('Label normal',      Offset + 6,
  1463.     ColorItem ('Label selected',    Offset + 7,
  1464.     ColorItem ('Label shortcut',    Offset + 8,
  1465.  
  1466.     ColorItem ('Button normal',     Offset + 9,
  1467.     ColorItem ('Button default',    Offset + 10,
  1468.     ColorItem ('Button selected',   Offset + 11,
  1469.     ColorItem ('Button disabled',   Offset + 12,
  1470.     ColorItem ('Button shortcut',   Offset + 13,
  1471.     ColorItem ('Button shadow',     Offset + 14,
  1472.  
  1473.     ColorItem ('Cluster normal',    Offset + 15,
  1474.     ColorItem ('Cluster selected',  Offset + 16,
  1475.     ColorItem ('Cluster shortcut',  Offset + 17,
  1476.  
  1477.     ColorItem ('Input normal',      Offset + 18,
  1478.     ColorItem ('Input selected',    Offset + 19,
  1479.     ColorItem ('Input arrow',       Offset + 20,
  1480.  
  1481.     ColorItem ('History button',    Offset + 21,
  1482.     ColorItem ('History sides',     Offset + 22,
  1483.     ColorItem ('History bar page',  Offset + 23,
  1484.     ColorItem ('History bar icons', Offset + 24,
  1485.  
  1486.     ColorItem ('List normal',       Offset + 25,
  1487.     ColorItem ('List focused',      Offset + 26,
  1488.     ColorItem ('List selected',     Offset + 27,
  1489.     ColorItem ('List divider',      Offset + 28,
  1490.  
  1491.     ColorItem('Information pane',  Offset + 29,
  1492.     Next))))))))))))))))))))))))))))));
  1493. end;
  1494.  
  1495. function HelpColorItems(const Next: PColorItem): PColorItem;
  1496.  
  1497. begin
  1498.   HelpColorItems :=
  1499.     ColorItem ('Frame passive',     128,
  1500.     ColorItem ('Frame active',      129,
  1501.     ColorItem ('Frame icons',       130,
  1502.     ColorItem ('Scroll bar page',   131,
  1503.     ColorItem ('Scroll bar icons',  132,
  1504.     ColorItem ('Normal text',       133,
  1505.     ColorItem ('Key word',          134,
  1506.     ColorItem ('Select key word',   135,
  1507.     Next))))))))
  1508. end;
  1509.  
  1510. function SysColorItems (const Next: PColorItem) : PColorItem;
  1511.  
  1512. begin
  1513.   SysColorItems :=
  1514.     ColorItem ('Shadow',       136,
  1515.     ColorItem ('System error', 137,
  1516.     ColorItem ('Index error',  138,
  1517.     Next)))
  1518. end;
  1519.  
  1520. var
  1521.  
  1522.   D : PColorDialog;
  1523.  
  1524. begin
  1525.   D := New (PColorDialog,Init ('',
  1526.   ColorGroup ('Desktop',     DesktopColorItems(nil),
  1527.   ColorGroup ('Menus',       MenuColorItems(nil),
  1528.   ColorGroup ('Gray Windows',WindowColorItems(wpGrayWindow,nil),
  1529.   ColorGroup ('Blue Windows',WindowColorItems(wpBlueWindow,nil),
  1530.   ColorGroup ('Cyan Windows',WindowColorItems(wpCyanWindow,nil),
  1531.   ColorGroup ('Gray Dialogs',DlgColorItems(dpGrayDialog,nil),
  1532.   ColorGroup ('Blue Dialogs',DlgColorItems(dpBlueDialog,nil),
  1533.   ColorGroup ('Cyan Dialogs',DlgColorItems(dpCyanDialog,nil),
  1534.   ColorGroup ('Help',        HelpColorItems(nil),
  1535.   ColorGroup ('System',      SysColorItems(nil),
  1536.   nil))))))))))));
  1537.   D^.HelpCtx := hcColorDialog;
  1538.   if ExecuteDialog (D,Application^.GetPalette) <> cmCancel then
  1539.   begin
  1540.     DoneMemory; {dispose all group buffers}
  1541.     ReDraw;     {redraw application with new palette}
  1542.     ShadowAttr := GetColor (136);   {tv shadow color}
  1543.     SysColorAttr := (GetColor (137) shl 8) or GetColor (137); {tv system error color}
  1544.     ErrorAttr := GetColor (138);    {tv palette index error color}
  1545.   end
  1546. end;
  1547.  
  1548. {
  1549. Force all oftileable windows to top and use Focus to cause call to
  1550. PView^.Valid and validate.
  1551. }
  1552.  
  1553. procedure TileableOnTop (P : PView); far;
  1554.  
  1555. begin
  1556.   if (P^.Options and ofTileable = ofTileable) then
  1557.     P^.Focus
  1558. end;
  1559.  
  1560. begin
  1561.   if Event.What = evCommand then {we need to see these before inherited call}
  1562.     case Event.Command of
  1563.       cmSaveAs  :
  1564.       begin
  1565.         TreeWindow ('Save As','*.SCR',cmSaveAs);
  1566.         ClearEvent (Event)
  1567.       end;
  1568.       cmCascade :
  1569.       begin
  1570.         UpdateStatus ('Cascading windows');
  1571.         Desktop^.ForEach (@TileableOnTop)
  1572.       end;
  1573.       cmTile :
  1574.       begin
  1575.         UpdateStatus ('Tiling windows');
  1576.         Desktop^.ForEach (@TileableOnTop)
  1577.       end;
  1578.       cmQuit :
  1579.       begin
  1580.         ClearDeskTop;                   {empty entire desk top}
  1581.         if DeskTop^.Current <> nil then {make sure nothing failed to close}
  1582.           ClearEvent (Event)
  1583.       end
  1584.     end;
  1585.   inherited HandleEvent (Event);
  1586.   case Event.What of
  1587.     evCommand:
  1588.     begin
  1589.       case Event.Command of             {process commands}
  1590.         cmOpenTable    : TreeWindow ('Open Table','*.DB',cmOpenTable);
  1591.         cmCreateTable  : TreeWindow ('Create Table','*.DB',cmCreateTable);
  1592.         cmCreateIndex  : TreeWindow ('Create Index','*.DB',cmCreateIndex);
  1593.         cmDeleteIndex  : TreeWindow ('Delete Index','*.DB',cmDeleteIndex);
  1594.         cmAppendTable  : TreeWindow ('Append Table To','*.DB',cmAppendTable);
  1595.         cmCopyTable    : TreeWindow ('Copy Table To','*.DB',cmCopyTable);
  1596.         cmRenameTable  : TreeWindow ('Rename Table To','*.DB',cmRenameTable);
  1597.         cmEmptyTable   : TreeWindow ('Empty Table','*.DB',cmEmptyTable);
  1598.         cmDeleteTable  : TreeWindow ('Delete Table','*.DB',cmDeleteTable);
  1599.         cmEncryptTable : TreeWindow ('Encrypt Table','*.DB',cmEncryptTable);
  1600.         cmDecryptTable : TreeWindow ('Decrypt Table','*.DB',cmDecryptTable);
  1601.         cmUpgradeTable : TreeWindow ('Upgrade Table','*.DB',cmUpgradeTable);
  1602.         cmSaveConfig   : TreeWindow ('Save Config Stream','*.CFG',cmSaveConfig);
  1603.         cmLoadConfig   : TreeWindow ('Load Config Stream','*.CFG',cmLoadConfig);
  1604.         cmFileBrowse   : TreeWindow ('File List Builder','*.DB',cmAddFile);
  1605.         cmOpen         : TreeWindow ('Open Text File','*.*',cmOpen);
  1606.         cmNew          : FileNew;
  1607.         cmShowClip     : ShowClip;
  1608.         cmNewFileList  : NewFileList;
  1609.         cmAddPassword  : AddPassword;
  1610.         cmEngineConfig : EngineConfig;
  1611.         cmVideoToggle  : ToggleVideo;
  1612.         cmViewDoc      : ViewTextFile (appDocName);
  1613.         cmCalendar     : Calendar;
  1614.         cmCalculator   : Calculator;
  1615.         cmAbout        : AboutBox;
  1616.         cmCloseAll     : ClearDeskTop;
  1617.         cmColors       : Colors
  1618.       else
  1619.         Exit
  1620.       end;
  1621.       ClearEvent (Event)
  1622.     end;
  1623.     evBroadcast :
  1624.     begin
  1625.       case Event.Command of {process broadcasts}
  1626.         cmOpenTable    : OpenTable (PDirWindow (Event.InfoPtr));
  1627.         cmCreateTable  : CreateTable (PDirWindow (Event.InfoPtr));
  1628.         cmCreateIndex  : CreateIndex (PDirWindow (Event.InfoPtr));
  1629.         cmDeleteIndex  : DeleteIndex (PDirWindow (Event.InfoPtr));
  1630.         cmAppendTable  : AppendTable (PDirWindow (Event.InfoPtr));
  1631.         cmCopyTable    : CopyTable (PDirWindow (Event.InfoPtr));
  1632.         cmRenameTable  : RenameTable (PDirWindow (Event.InfoPtr));
  1633.         cmEmptyTable   : EmptyTable (PDirWindow (Event.InfoPtr));
  1634.         cmDeleteTable  : DeleteTable (PDirWindow (Event.InfoPtr));
  1635.         cmEncryptTable : EncryptTable (PDirWindow (Event.InfoPtr));
  1636.         cmDecryptTable : DecryptTable (PDirWindow (Event.InfoPtr));
  1637.         cmUpgradeTable : UpgradeTable (PDirWindow (Event.InfoPtr));
  1638.         cmSaveConfig   : SaveConfigFile (PDirWindow (Event.InfoPtr));
  1639.         cmLoadConfig   : LoadConfigFile (PDirWindow (Event.InfoPtr));
  1640.         cmAddFile      : AddFileToList (PDirWindow (Event.InfoPtr));
  1641.         cmOpen         : FileOpen (PDirWindow (Event.InfoPtr));
  1642.         cmSaveAs       : SaveFileAs (PDirWindow (Event.InfoPtr))
  1643.       end
  1644.     end
  1645.   end
  1646. end;
  1647.  
  1648. {
  1649. Assign desk top pattern char.
  1650. }
  1651.  
  1652. procedure TCyberBase.InitDeskTop;
  1653.  
  1654. begin
  1655.   inherited InitDeskTop;
  1656.   DeskTop^.Background^.Pattern := '▒' {new wall paper}
  1657. end;
  1658.  
  1659. procedure TCyberBase.InitMenuBar;
  1660.  
  1661. var
  1662.  
  1663.   R : TRect;
  1664.  
  1665. begin
  1666.   GetExtent (R);
  1667.   R.B.Y := R.A.Y+1;
  1668.   MenuBar := New (PMenuBar,Init (R,NewMenu (
  1669.     NewSubMenu ('~F~ile',hcFile,NewMenu (
  1670.       NewSubMenu ('~T~able',hcTable,NewMenu (
  1671.         NewItem ('~N~ew...','F4',kbF4,cmCreateTable,hcNew,
  1672.         NewItem ('~O~pen...','F3',kbF3,cmOpenTable,hcOpen,
  1673.         NewItem ('~A~ppend...','',kbNoKey,cmAppendTable,hcAppend,
  1674.         NewItem ('~C~opy...','',kbNoKey,cmCopyTable,hcCopyTable,
  1675.         NewItem ('~R~ename...','',kbNoKey,cmRenameTable,hcRename,
  1676.         NewItem ('~E~mpty...','',kbNoKey,cmEmptyTable,hcEmpty,
  1677.         NewItem ('~D~elete...','',kbNoKey,cmDeleteTable,hcDelete,
  1678.         NewItem ('~U~pgrade...','',kbNoKey,cmUpgradeTable,hcUpgrade,
  1679.         nil))))))))),
  1680.       NewSubMenu ('~I~ndex',hcIndex,NewMenu (
  1681.         NewItem ('~N~ew...','',kbNoKey,cmCreateIndex,hcNewIndex,
  1682.         NewItem ('~D~elete...','',kbNoKey,cmDeleteIndex,hcDeleteIndex,
  1683.         nil))),
  1684.       NewSubMenu ('~A~SCII',hcASCII,NewMenu (
  1685.         NewItem ('~N~ew', '', kbNoKey, cmNew, hcNewText,
  1686.         NewItem ('~O~pen...', '', kbNoKey, cmOpen, hcOpenText,
  1687.         NewItem ('~S~ave', '', kbNoKey, cmSave, hcSaveText,
  1688.         NewItem ('Sa~v~e as...', '', kbNoKey, cmSaveAs, hcSaveAsText,
  1689.         NewItem ('Save a~l~l', '', kbNoKey, cmSaveAll, hcSaveAllText,
  1690.         nil)))))),
  1691.       NewSubMenu ('~S~ecurity',hcSecurity,NewMenu (
  1692.         NewItem ('~A~dd password...','',kbNoKey,cmAddPassword,hcAddPassword,
  1693.         NewItem ('~E~ncrypt...','',kbNoKey,cmEncryptTable,hcEncrypt,
  1694.         NewItem ('~D~ecrypt...','',kbNoKey,cmDecryptTable,hcDecrypt,
  1695.         nil)))),
  1696.       NewSubMenu ('~L~ist',hcList,NewMenu (
  1697.         NewItem ('~N~ew','',kbNoKey,cmNewFileList,hcNewFileList,
  1698.         NewItem ('~B~uilder...','',kbNoKey,cmFileBrowse,hcFileListBuild,
  1699.         nil))),
  1700.       NewSubMenu ('~C~onfig',hcConfig,NewMenu (
  1701.         NewItem ('~L~oad...','Ctrl+F3',kbCtrlF3,cmLoadConfig,hcLoadFile,
  1702.         NewItem ('~S~ave...','Ctrl+F2',kbCtrlF2,cmSaveConfig,hcSaveFile,
  1703.         nil))),
  1704.       NewLine (
  1705.       NewItem ('A~b~out','',kbNoKey,cmAbout,hcAbout,
  1706.       NewLine (
  1707.       NewItem ('E~x~it','Alt+X',kbAltX,cmQuit,hcExit,
  1708.       nil))))))))))),
  1709.     NewSubMenu('~E~dit', hcEdit, NewMenu(
  1710.       StdEditMenuItems(
  1711.       NewLine(
  1712.       NewItem('~S~how clipboard', '', kbNoKey, cmShowClip, hcShowClip,
  1713.       nil)))),
  1714.     NewSubMenu('~S~earch', hcSearch, NewMenu(
  1715.       NewItem('~F~ind...', '', kbNoKey, cmFind, hcFind,
  1716.       NewItem('~R~eplace...', '', kbNoKey, cmReplace, hcReplace,
  1717.       NewItem('~S~earch again', '', kbNoKey, cmSearchAgain, hcSearchAgain,
  1718.       nil)))),
  1719.     NewSubMenu ('~T~ools',hcTools,NewMenu (
  1720.       NewItem ('~C~alendar','',kbNoKey,cmCalendar,hcSCalendar,
  1721.       NewItem ('Ca~l~culator','',kbNoKey,cmCalculator,hcSCalculator,
  1722.       NewItem ('~V~iew doc','',kbNoKey,cmViewDoc,hcViewDoc,
  1723.       nil)))),
  1724.     NewSubMenu ('~O~ptions',hcOptions,NewMenu (
  1725.       NewItem ('~E~ngine...','',kbNoKey,cmEngineConfig,hcEngine,
  1726.       NewItem ('~C~olors...','',kbNoKey,cmColors,hcOColors,
  1727.       NewItem ('~V~ideo toggle','',kbNoKey,cmVideoToggle,hcVideoToggle,
  1728.       nil)))),
  1729.     NewSubMenu ('~W~indow',hcWindows,NewMenu(
  1730.       StdWindowMenuItems (
  1731.       nil)),nil)))))))))
  1732. end;
  1733.  
  1734. procedure TCyberBase.InitStatusLine;
  1735.  
  1736. var
  1737.  
  1738.   R : TRect;
  1739.  
  1740. begin
  1741.   GetExtent (R);
  1742.   R.A.Y := R.B.Y-1;
  1743.   StatusLine := New (PStatusLine,Init(R,
  1744.     NewStatusDef (0,$FFFF,
  1745.       NewStatusKey ('~F1~ Help', kbF1, cmHelp,
  1746.       NewStatusKey ('~F3~ Open',kbF3,cmOpenTable,
  1747.       NewStatusKey ('~Alt+F3~ Close',kbAltF3,cmClose,
  1748.       NewStatusKey ('~Alt+X~ Exit',kbAltX,cmQuit,
  1749.       NewStatusKey ('',kbCtrlF2,cmSaveConfig,
  1750.       NewStatusKey ('',kbCtrlF3,cmLoadConfig,
  1751.       NewStatusKey ('',kbF4,cmCreateTable,
  1752.       NewStatusKey ('',kbCtrlF5,cmResize,
  1753.       NewStatusKey ('',kbF10,cmMenu,
  1754.       nil))))))))),nil)))
  1755. end;
  1756.  
  1757. {
  1758. Let user know if heap allocation cuts into the safety pool.
  1759. }
  1760.  
  1761. procedure TCyberBase.OutOfMemory;
  1762.  
  1763. begin
  1764.   MessageBox ('Not enough memory available to complete operation.  Try closing some windows!',
  1765.   nil,mfError+mfOkButton)
  1766. end;
  1767.  
  1768. {
  1769. Load desk top from stream.
  1770. }
  1771.  
  1772. procedure TCyberBase.LoadDesktop (var S : TStream);
  1773.  
  1774. var
  1775.  
  1776.   Pal : PString;
  1777.  
  1778. begin
  1779.   Pal := S.ReadStr;
  1780.   if Pal <> nil then
  1781.   begin
  1782.     Application^.GetPalette^ := Pal^;
  1783.     DoneMemory;
  1784.     DisposeStr (Pal)
  1785.   end
  1786. end;
  1787.  
  1788. {
  1789. Store desk top on stream.
  1790. }
  1791.  
  1792. procedure TCyberBase.StoreDesktop(var S: TStream);
  1793.  
  1794. var
  1795.  
  1796.   Pal: PString;
  1797.  
  1798. begin
  1799.   Pal := @Application^.GetPalette^;
  1800.   S.WriteStr (Pal)
  1801. end;
  1802.  
  1803. var
  1804.  
  1805.   CBApp : TCyberBase;
  1806.  
  1807. begin
  1808.   CBApp.Init;
  1809.   SysErrorFunc := AppSystemError;
  1810.   CBApp.Run;
  1811.   CBApp.Done
  1812. end.
  1813.